{
  "cells": [
    {
      "cell_type": "markdown",
      "id": "4cbf2458",
      "metadata": {
        "id": "4cbf2458"
      },
      "source": [
        "[![Open in Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/langchain-ai/langchain-academy/blob/main/module-1/chain.ipynb) [![Open in LangChain Academy](https://cdn.prod.website-files.com/65b8cd72835ceeacd4449a53/66e9eba12c7b7688aa3dbb5e_LCA-badge-green.svg)](https://academy.langchain.com/courses/take/intro-to-langgraph/lessons/58238466-lesson-4-chain)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "ee55d3da-c53a-4c76-b46f-8e0d602e072e",
      "metadata": {
        "id": "ee55d3da-c53a-4c76-b46f-8e0d602e072e"
      },
      "source": [
        "# Chain\n",
        "\n",
        "## Review\n",
        "\n",
        "We built a simple graph with nodes, normal edges, and conditional edges.\n",
        "\n",
        "## Goals\n",
        "\n",
        "Now, let's build up to a simple chain that combines 4 [concepts](https://python.langchain.com/v0.2/docs/concepts/):\n",
        "\n",
        "* Using [chat messages](https://python.langchain.com/v0.2/docs/concepts/#messages) as our graph state\n",
        "* Using [chat models](https://python.langchain.com/v0.2/docs/concepts/#chat-models) in graph nodes\n",
        "* [Binding tools](https://python.langchain.com/v0.2/docs/concepts/#tools) to our chat model\n",
        "* [Executing tool calls](https://python.langchain.com/v0.2/docs/concepts/#functiontool-calling) in graph nodes\n",
        "\n",
        "![Screenshot 2024-08-21 at 9.24.03 AM.png](https://cdn.prod.website-files.com/65b8cd72835ceeacd4449a53/66dbab08dd607b08df5e1101_chain1.png)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 1,
      "id": "a55e2e80-a718-4aaf-99b9-371157b34a4b",
      "metadata": {
        "id": "a55e2e80-a718-4aaf-99b9-371157b34a4b"
      },
      "outputs": [],
      "source": [
        "%%capture --no-stderr\n",
        "%pip install --quiet -U langchain-google-genai langchain_core langgraph"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "ae5ac2d0-c7b0-4a20-86e5-4b6ed15ec20e",
      "metadata": {
        "id": "ae5ac2d0-c7b0-4a20-86e5-4b6ed15ec20e"
      },
      "source": [
        "## Messages\n",
        "\n",
        "Chat models can use [`messages`](https://python.langchain.com/v0.2/docs/concepts/#messages), which capture different roles within a conversation.\n",
        "\n",
        "LangChain supports various message types, including `HumanMessage`, `AIMessage`, `SystemMessage`, and `ToolMessage`.\n",
        "\n",
        "These represent a message from the user, from chat model, for the chat model to instruct behavior, and from a tool call.\n",
        "\n",
        "Let's create a list of messages.\n",
        "\n",
        "Each message can be supplied with a few things:\n",
        "\n",
        "* `content` - content of the message\n",
        "* `name` - optionally, a message author\n",
        "* `response_metadata` - optionally, a dict of metadata (e.g., often populated by model provider for `AIMessages`)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 2,
      "id": "866b5321-a238-4a9e-af9e-f11a131b5f11",
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "866b5321-a238-4a9e-af9e-f11a131b5f11",
        "outputId": "afafbcdd-31eb-484b-9ed7-b8e4dfd3ab7c"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "==================================\u001b[1m Ai Message \u001b[0m==================================\n",
            "Name: Model\n",
            "\n",
            "So you said you were researching ocean mammals?\n",
            "================================\u001b[1m Human Message \u001b[0m=================================\n",
            "Name: Lance\n",
            "\n",
            "Yes, that's right.\n",
            "==================================\u001b[1m Ai Message \u001b[0m==================================\n",
            "Name: Model\n",
            "\n",
            "Great, what would you like to learn about.\n",
            "================================\u001b[1m Human Message \u001b[0m=================================\n",
            "Name: Lance\n",
            "\n",
            "I want to learn about the best place to see Orcas in the US.\n"
          ]
        }
      ],
      "source": [
        "from pprint import pprint\n",
        "from langchain_core.messages import AIMessage, HumanMessage\n",
        "\n",
        "messages = [AIMessage(content=f\"So you said you were researching ocean mammals?\", name=\"Model\")]\n",
        "messages.append(HumanMessage(content=f\"Yes, that's right.\",name=\"Lance\"))\n",
        "messages.append(AIMessage(content=f\"Great, what would you like to learn about.\", name=\"Model\"))\n",
        "messages.append(HumanMessage(content=f\"I want to learn about the best place to see Orcas in the US.\", name=\"Lance\"))\n",
        "\n",
        "for m in messages:\n",
        "    m.pretty_print()"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "0ca48df0-b639-4ff1-a777-ffe2185d991e",
      "metadata": {
        "id": "0ca48df0-b639-4ff1-a777-ffe2185d991e"
      },
      "source": [
        "## Chat Models\n",
        "\n",
        "[Chat models](https://python.langchain.com/v0.2/docs/concepts/#chat-models) can use a sequence of message as input and support message types, as discussed above.\n",
        "\n",
        "There are [many](https://python.langchain.com/v0.2/docs/concepts/#chat-models) to choose from! Let's work with Gemini.\n",
        "\n",
        "Let's check that your `GEMINI_API_KEY` is set and, if not, you will be asked to enter it."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 3,
      "id": "2652d5ec-7602-4220-bc6e-b90783ab287b",
      "metadata": {
        "id": "2652d5ec-7602-4220-bc6e-b90783ab287b"
      },
      "outputs": [],
      "source": [
        "from google.colab import userdata\n",
        "google_api_key = userdata.get('GEMINI_API_KEY')"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "ceae53d4-14f5-4bf3-a953-cc465240f5b5",
      "metadata": {
        "id": "ceae53d4-14f5-4bf3-a953-cc465240f5b5"
      },
      "source": [
        "We can load a chat model and invoke it with out list of messages.\n",
        "\n",
        "We can see that the result is an `AIMessage` with specific `response_metadata`."
      ]
    },
    {
      "cell_type": "markdown",
      "id": "39747099",
      "metadata": {},
      "source": [
        "**Note:** Obtain the necessary json key from the Google Cloud Console by following the instructions outlined in step 21_langchain_ecosystem/langchain/-01_gemini_standalone/Gemini_API_python.ipynb file. Once acquired, load the json key in Google Colab to proceed with the project."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 5,
      "id": "95b99ad4-5753-49d3-a916-a9e949722c01",
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 187
        },
        "id": "95b99ad4-5753-49d3-a916-a9e949722c01",
        "outputId": "2f258a9e-2867-43fc-df19-90f23d839ecd"
      },
      "outputs": [
        {
          "name": "stderr",
          "output_type": "stream",
          "text": [
            "/Users/mjs/Documents/code/panaversity-official/learn-applied-generative-ai-fundamentals/.conda/lib/python3.12/site-packages/tqdm/auto.py:21: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html\n",
            "  from .autonotebook import tqdm as notebook_tqdm\n"
          ]
        },
        {
          "data": {
            "text/plain": [
              "langchain_core.messages.ai.AIMessage"
            ]
          },
          "execution_count": 5,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "from langchain_google_genai import ChatGoogleGenerativeAI\n",
        "llm: ChatGoogleGenerativeAI = ChatGoogleGenerativeAI(model=\"gemini-1.5-flash\", api_key=google_api_key)\n",
        "result = llm.invoke(messages)\n",
        "type(result)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 6,
      "id": "88d60338-c892-4d04-a83f-878de4a76a6a",
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "88d60338-c892-4d04-a83f-878de4a76a6a",
        "outputId": "9a3456f6-f9fc-49d4-f4ce-69419bb0ddb0"
      },
      "outputs": [
        {
          "data": {
            "text/plain": [
              "AIMessage(content=\"That's a great question! The best place to see Orcas in the US depends on what kind of experience you're looking for. \\n\\nHere are some of the top spots, with different pros and cons:\\n\\n**For the best chance of seeing Orcas in the wild:**\\n\\n* **The San Juan Islands, Washington:** This is considered one of the best places in the world to see Orcas, particularly the Southern Resident Killer Whales. They are known to frequent the waters around the islands, especially during the summer months. You can go on whale watching tours, kayak, or even just keep an eye out from the shore.\\n    * **Pros:** High chance of seeing Orcas, beautiful scenery, multiple ways to experience it.\\n    * **Cons:** Can be crowded during peak season, tours can be expensive.\\n\\n* **Alaska:** While Orcas can be spotted in various locations in Alaska, the Inside Passage is particularly known for its abundant marine life, including Orcas. You can go on whale watching tours, cruise ships, or even fly over the area for a unique perspective.\\n    * **Pros:** Diverse marine life, stunning scenery, multiple ways to experience it.\\n    * **Cons:** Can be expensive, unpredictable weather, long travel time.\\n\\n* **The Pacific Coast of California:**  While less frequent than in Washington or Alaska, Orcas do pass through the waters of California, particularly during the winter months. You can go on whale watching tours or keep an eye out from the shore.\\n    * **Pros:** More affordable than Alaska or Washington, milder weather.\\n    * **Cons:** Lower chance of seeing Orcas, can be less predictable.\\n\\n**For a more controlled experience:**\\n\\n* **SeaWorld Parks:** While not in the wild, SeaWorld parks in California, Florida, and Texas offer opportunities to see Orcas in captivity. They also have educational programs about Orca behavior and conservation.\\n    * **Pros:** Guaranteed to see Orcas, educational opportunities.\\n    * **Cons:** Ethical concerns surrounding keeping Orcas in captivity, limited natural behavior.\\n\\n**Important Considerations:**\\n\\n* **Time of year:** Orcas migrate, so the best time to see them varies depending on the location.\\n* **Weather:**  The weather can affect whale watching tours, so check the forecast before you go.\\n* **Ethical considerations:** Choose reputable tour operators that prioritize the well-being of the whales.\\n\\nWould you like to learn more about any of these locations or about ethical whale watching? \\n\", additional_kwargs={}, response_metadata={'prompt_feedback': {'block_reason': 0, 'safety_ratings': []}, 'finish_reason': 'STOP', 'safety_ratings': [{'category': 'HARM_CATEGORY_SEXUALLY_EXPLICIT', 'probability': 'NEGLIGIBLE', 'blocked': False}, {'category': 'HARM_CATEGORY_HATE_SPEECH', 'probability': 'NEGLIGIBLE', 'blocked': False}, {'category': 'HARM_CATEGORY_HARASSMENT', 'probability': 'NEGLIGIBLE', 'blocked': False}, {'category': 'HARM_CATEGORY_DANGEROUS_CONTENT', 'probability': 'NEGLIGIBLE', 'blocked': False}]}, id='run-fe6cecf6-d900-4c54-b023-5ca5d76a8990-0', usage_metadata={'input_tokens': 46, 'output_tokens': 521, 'total_tokens': 567})"
            ]
          },
          "execution_count": 6,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "result"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 7,
      "id": "c3a29654-6b8e-4eda-9cec-22fabb9b8620",
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "c3a29654-6b8e-4eda-9cec-22fabb9b8620",
        "outputId": "1c8b59a2-4e99-40d9-e625-b9eb5be5334a"
      },
      "outputs": [
        {
          "data": {
            "text/plain": [
              "{'prompt_feedback': {'block_reason': 0, 'safety_ratings': []},\n",
              " 'finish_reason': 'STOP',\n",
              " 'safety_ratings': [{'category': 'HARM_CATEGORY_SEXUALLY_EXPLICIT',\n",
              "   'probability': 'NEGLIGIBLE',\n",
              "   'blocked': False},\n",
              "  {'category': 'HARM_CATEGORY_HATE_SPEECH',\n",
              "   'probability': 'NEGLIGIBLE',\n",
              "   'blocked': False},\n",
              "  {'category': 'HARM_CATEGORY_HARASSMENT',\n",
              "   'probability': 'NEGLIGIBLE',\n",
              "   'blocked': False},\n",
              "  {'category': 'HARM_CATEGORY_DANGEROUS_CONTENT',\n",
              "   'probability': 'NEGLIGIBLE',\n",
              "   'blocked': False}]}"
            ]
          },
          "execution_count": 7,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "result.response_metadata"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "4718bd5c-5314-4405-a164-f1fe912ae306",
      "metadata": {
        "id": "4718bd5c-5314-4405-a164-f1fe912ae306"
      },
      "source": [
        "## Tools\n",
        "\n",
        "Tools are useful whenever you want a model to interact with external systems.\n",
        "\n",
        "External systems (e.g., APIs) often require a particular input schema or payload, rather than natural language.\n",
        "\n",
        "When we bind an API, for example, as a tool we given the model awareness of the required input schema.\n",
        "\n",
        "The model will choose to call a tool based upon the natural language input from the user.\n",
        "\n",
        "And, it will return an output that adheres to the tool's schema.\n",
        "\n",
        "[Many LLM providers support tool calling](https://python.langchain.com/v0.1/docs/integrations/chat/) and [tool calling interface](https://blog.langchain.dev/improving-core-tool-interfaces-and-docs-in-langchain/) in LangChain is simple.\n",
        "\n",
        "You can simply pass any Python `function` into `ChatModel.bind_tools(function)`.\n",
        "\n",
        "![Screenshot 2024-08-19 at 7.46.28 PM.png](https://cdn.prod.website-files.com/65b8cd72835ceeacd4449a53/66dbab08dc1c17a7a57f9960_chain2.png)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "17a942b1",
      "metadata": {
        "id": "17a942b1"
      },
      "source": [
        "Let's showcase a simple example of tool calling!\n",
        "\n",
        "The `multiply` function is our tool."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 8,
      "id": "928faf56-1a1a-4c5f-b97d-bd64d8e166d1",
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "928faf56-1a1a-4c5f-b97d-bd64d8e166d1",
        "outputId": "8c1c2bcc-8186-43d8-a54f-73b825133397"
      },
      "outputs": [
        {
          "name": "stderr",
          "output_type": "stream",
          "text": [
            "Key 'title' is not supported in schema, ignoring\n",
            "Key 'title' is not supported in schema, ignoring\n",
            "Key 'title' is not supported in schema, ignoring\n"
          ]
        }
      ],
      "source": [
        "def multiply(a: int, b: int) -> int:\n",
        "    \"\"\"Multiply a and b.\n",
        "\n",
        "    Args:\n",
        "        a: first int\n",
        "        b: second int\n",
        "    \"\"\"\n",
        "    return a * b\n",
        "\n",
        "llm_with_tools: ChatGoogleGenerativeAI = llm.bind_tools([multiply])"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "Y4oOqXZW6Tms",
      "metadata": {
        "id": "Y4oOqXZW6Tms"
      },
      "source": [
        "**Note:** Warning indicates that the title key is being generated internally, likely within LangGraph or the Gemini integration when the tool is being bound, rather than being passed explicitly. So ignore the warning\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "8a3f9dba",
      "metadata": {
        "id": "8a3f9dba"
      },
      "source": [
        "If we pass an input - e.g., `\"What is 2 multiplied by 3\"` - we see a function_call returned.\n",
        "\n",
        "The function_call has specific arguments that match the input schema of our function along with the name of the function to call.\n",
        "\n",
        "```\n",
        "{'name': 'multiply', 'arguments': '{\"b\": 3.0, \"a\": 2.0}'}\n",
        "```\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 9,
      "id": "9edbe13e-cc72-4685-ac97-2ebb4ceb2544",
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "9edbe13e-cc72-4685-ac97-2ebb4ceb2544",
        "outputId": "aca9c8e5-8d07-4fd2-9ee2-06c7844ef633"
      },
      "outputs": [
        {
          "data": {
            "text/plain": [
              "AIMessage(content='', additional_kwargs={'function_call': {'name': 'multiply', 'arguments': '{\"a\": 2.0, \"b\": 3.0}'}}, response_metadata={'prompt_feedback': {'block_reason': 0, 'safety_ratings': []}, 'finish_reason': 'STOP', 'safety_ratings': [{'category': 'HARM_CATEGORY_SEXUALLY_EXPLICIT', 'probability': 'NEGLIGIBLE', 'blocked': False}, {'category': 'HARM_CATEGORY_HARASSMENT', 'probability': 'NEGLIGIBLE', 'blocked': False}, {'category': 'HARM_CATEGORY_DANGEROUS_CONTENT', 'probability': 'NEGLIGIBLE', 'blocked': False}, {'category': 'HARM_CATEGORY_HATE_SPEECH', 'probability': 'NEGLIGIBLE', 'blocked': False}]}, id='run-c75c0c03-940e-48be-9775-337e63992cff-0', tool_calls=[{'name': 'multiply', 'args': {'a': 2.0, 'b': 3.0}, 'id': 'd5af761a-59ae-4dd2-a481-bb29334b35c0', 'type': 'tool_call'}], usage_metadata={'input_tokens': 71, 'output_tokens': 18, 'total_tokens': 89})"
            ]
          },
          "execution_count": 9,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "function_call = llm_with_tools.invoke([HumanMessage(content=f\"What is 2 multiplied by 3\", name=\"Lance\")])\n",
        "function_call"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 10,
      "id": "a78178cb-fa43-45b5-be5e-5a22bda5a5e7",
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "a78178cb-fa43-45b5-be5e-5a22bda5a5e7",
        "outputId": "b86cc538-440e-465f-b1df-9b353fc971d5"
      },
      "outputs": [
        {
          "data": {
            "text/plain": [
              "{'name': 'multiply', 'arguments': '{\"a\": 2.0, \"b\": 3.0}'}"
            ]
          },
          "execution_count": 10,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "function_call.additional_kwargs['function_call']"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "21c10f9a-2372-486b-9305-55b7c41ecd6e",
      "metadata": {
        "id": "21c10f9a-2372-486b-9305-55b7c41ecd6e"
      },
      "source": [
        "## Using messages as state\n",
        "\n",
        "With these foundations in place, we can now use [`messages`](https://python.langchain.com/v0.2/docs/concepts/#messages) in our graph state.\n",
        "\n",
        "Let's define our state, `MessagesState`, as a `TypedDict` with a single key: `messages`.\n",
        "\n",
        "`messages` is simply a list of messages, as we defined above (e.g., `HumanMessage`, etc)."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 11,
      "id": "3699dd5c-398c-43c7-b496-fd87e55e11ca",
      "metadata": {
        "id": "3699dd5c-398c-43c7-b496-fd87e55e11ca"
      },
      "outputs": [],
      "source": [
        "from typing_extensions import TypedDict\n",
        "from langchain_core.messages import AnyMessage\n",
        "\n",
        "class MessagesState(TypedDict):\n",
        "    messages: list[AnyMessage]"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "211cba3e-ebba-4b91-a539-1cbc28b4a40e",
      "metadata": {
        "id": "211cba3e-ebba-4b91-a539-1cbc28b4a40e"
      },
      "source": [
        "## Reducers\n",
        "\n",
        "Now, we have a minor problem!\n",
        "\n",
        "As we discussed, each node will return a new value for our state key `messages`.\n",
        "\n",
        "But, this new value will [will override](https://langchain-ai.github.io/langgraph/concepts/low_level/#reducers) the prior `messages` value.\n",
        "\n",
        "As our graph runs, we want to **append** messages to to our `messages` state key.\n",
        "\n",
        "We can use [reducer functions](https://langchain-ai.github.io/langgraph/concepts/low_level/#reducers) address this.\n",
        "\n",
        "Reducers allow us to specify how state updates are performed.\n",
        "\n",
        "If no reducer function is specified, then it is assumed that updates to the key should *override it* as we saw before.\n",
        "\n",
        "But, to append messages, we can use the pre-built `add_messages` reducer.\n",
        "\n",
        "This ensures that any messages are appended to the existing list of messages.\n",
        "\n",
        "We annotate simply need to annotate our `messages` key with the `add_messages` reducer function as metadata."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 12,
      "id": "6b33eb72-3197-4870-b9a3-0da8056c40c5",
      "metadata": {
        "id": "6b33eb72-3197-4870-b9a3-0da8056c40c5"
      },
      "outputs": [],
      "source": [
        "from typing import Annotated\n",
        "from langgraph.graph.message import add_messages\n",
        "\n",
        "class MessagesState(TypedDict):\n",
        "    messages: Annotated[list[AnyMessage], add_messages]"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "3663e574-ba15-46be-a37c-48c8052d693b",
      "metadata": {
        "id": "3663e574-ba15-46be-a37c-48c8052d693b"
      },
      "source": [
        "Since having a list of messages in graph state is so common, LangGraph has a pre-built [`MessagesState`](https://langchain-ai.github.io/langgraph/concepts/low_level/#messagesstate)!\n",
        "\n",
        "`MessagesState` is defined:\n",
        "\n",
        "* With a pre-build single `messages` key\n",
        "* This is a list of `AnyMessage` objects\n",
        "* It uses the `add_messages` reducer\n",
        "\n",
        "We'll usually use `MessagesState` because it is less verbose than defining a custom `TypedDict`, as shown above."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 13,
      "id": "9ab516ee-eab1-4856-8210-99f1fe499672",
      "metadata": {
        "id": "9ab516ee-eab1-4856-8210-99f1fe499672"
      },
      "outputs": [],
      "source": [
        "from langgraph.graph import MessagesState\n",
        "\n",
        "class MessagesState(MessagesState):\n",
        "    # Add any keys needed beyond messages, which is pre-built\n",
        "    pass"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "36b0fff7-60a2-4582-8f12-3a3ab6633d6c",
      "metadata": {
        "id": "36b0fff7-60a2-4582-8f12-3a3ab6633d6c"
      },
      "source": [
        "To go a bit deeper, we can see how the `add_messages` reducer works in isolation."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 14,
      "id": "23ffea76-16a5-4053-a1bc-91e0101d91dc",
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "23ffea76-16a5-4053-a1bc-91e0101d91dc",
        "outputId": "f9de81ea-e35e-4325-c60c-c199663690e9"
      },
      "outputs": [
        {
          "data": {
            "text/plain": [
              "[AIMessage(content='Hello! How can I assist you?', additional_kwargs={}, response_metadata={}, name='Model', id='15fa1c2a-acc2-4fe6-aad6-fd92010aa570'),\n",
              " HumanMessage(content=\"I'm looking for information on marine biology.\", additional_kwargs={}, response_metadata={}, name='Lance', id='1f5c3fea-0aa7-4984-9e28-9254512b8747'),\n",
              " AIMessage(content='Sure, I can help with that. What specifically are you interested in?', additional_kwargs={}, response_metadata={}, name='Model', id='1a3c5f69-de08-4ce0-9b09-ff5fb1dd0d05')]"
            ]
          },
          "execution_count": 14,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "# Initial state\n",
        "initial_messages = [AIMessage(content=\"Hello! How can I assist you?\", name=\"Model\"),\n",
        "                    HumanMessage(content=\"I'm looking for information on marine biology.\", name=\"Lance\")\n",
        "                   ]\n",
        "\n",
        "# New message to add\n",
        "new_message = AIMessage(content=\"Sure, I can help with that. What specifically are you interested in?\", name=\"Model\")\n",
        "\n",
        "# Test\n",
        "add_messages(initial_messages , new_message)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "485adccc-f262-49dd-af4f-a30e9b6a48e2",
      "metadata": {
        "id": "485adccc-f262-49dd-af4f-a30e9b6a48e2"
      },
      "source": [
        "## Our graph\n",
        "\n",
        "Now, lets use `MessagesState` with a graph."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 15,
      "id": "b5306639-7e6a-44be-8471-8d2631701cfb",
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 251
        },
        "id": "b5306639-7e6a-44be-8471-8d2631701cfb",
        "outputId": "c948ed54-0581-4282-d5fe-6e526fe7c567"
      },
      "outputs": [
        {
          "data": {
            "image/jpeg": "/9j/4AAQSkZJRgABAQAAAQABAAD/4gHYSUNDX1BST0ZJTEUAAQEAAAHIAAAAAAQwAABtbnRyUkdCIFhZWiAH4AABAAEAAAAAAABhY3NwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAA9tYAAQAAAADTLQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAlkZXNjAAAA8AAAACRyWFlaAAABFAAAABRnWFlaAAABKAAAABRiWFlaAAABPAAAABR3dHB0AAABUAAAABRyVFJDAAABZAAAAChnVFJDAAABZAAAAChiVFJDAAABZAAAAChjcHJ0AAABjAAAADxtbHVjAAAAAAAAAAEAAAAMZW5VUwAAAAgAAAAcAHMAUgBHAEJYWVogAAAAAAAAb6IAADj1AAADkFhZWiAAAAAAAABimQAAt4UAABjaWFlaIAAAAAAAACSgAAAPhAAAts9YWVogAAAAAAAA9tYAAQAAAADTLXBhcmEAAAAAAAQAAAACZmYAAPKnAAANWQAAE9AAAApbAAAAAAAAAABtbHVjAAAAAAAAAAEAAAAMZW5VUwAAACAAAAAcAEcAbwBvAGcAbABlACAASQBuAGMALgAgADIAMAAxADb/2wBDAAMCAgMCAgMDAwMEAwMEBQgFBQQEBQoHBwYIDAoMDAsKCwsNDhIQDQ4RDgsLEBYQERMUFRUVDA8XGBYUGBIUFRT/2wBDAQMEBAUEBQkFBQkUDQsNFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBT/wAARCADqAKEDASIAAhEBAxEB/8QAHQABAAIDAQEBAQAAAAAAAAAAAAUGAwQHCAIBCf/EAE8QAAEDAwEDBggKBwUGBwAAAAEAAgMEBREGBxIhExQVMZTTCBYiQVFUVmEXIzI0VXFydLHRNkKBkpWhsiQmN3OTCSVDYpHSMzVEUlNlpP/EABoBAQEAAwEBAAAAAAAAAAAAAAABAgMGBAX/xAAyEQEAAQIBCQYGAwEBAAAAAAAAAQIRAwQSFCExUXGR0UFSYWKSoQUTIzOxwVPh8DKB/9oADAMBAAIRAxEAPwD+qaIiAiIgItC9XiGx0LqmVkkziQyKnhAMk0h+SxgJAyT6SAOJJABIhhpOXUDeW1LLzrfH/lcMhFHFx6jwBlPmLn8D5mtzhbaaImM6qbR/ti2TE+obVSyFk1zo4njra+oY0/8AQlY/Gqy/TFB2ln5rHDo6wU7d2Kx22NvXhlJGB+CyeKtl+h6DszPyWf0fH2XUeNVl+mKDtLPzTxqsv0xQdpZ+aeKtl+h6DszPyTxVsv0PQdmZ+SfR8fY1HjVZfpig7Sz808arL9MUHaWfmnirZfoeg7Mz8k8VbL9D0HZmfkn0fH2NR41WX6YoO0s/NfUepLRM8NjutFI49QbUMJ/FfPirZfoeg7Mz8l8S6RsUzCySy26Rh62upIyD/JPo+PsmpLAggEHIK/VWDomK0/HacmNkmBLuax8aOX/lfF1NHvj3Xe8jgZSxXoXiCUSQOo66nfydTSPOTE/3H9ZpHFrvOD5jkDGqiLZ1E3j3LbkmiItKCIiAiIgIiICIiCsDF32gvbJh0NmpGSRtOeE8xeC70ZEbMA+iR3pVnVYto5ntBvcT8jntHTVMZxwduGSN4z6R8X+8FZ16MbbTEbLR+Lz73WRERedHL4PCR0JdaDUNRZbpNeZLLR1FbKymoKosmZC7ceYpOSLZQHkNJjL8ZWlobwltL6l2Q27Xd1NZZaaWCm53DJbas8nUTMa4RQ5hDqgZdgPia5rvMVzbZZbr7TapvGk9IWTVdn2dVVorzLbNW2808VqrnvxHHRTO8qSN+/ISwF7W4BDhnC0bTqTWVN4Oug9NUGnta6dqdPvtlo1S6jtMja4UbIXxzOoTunlfjIo8vh3iGPyOPUHcovCA2fy6AqtajUcLNNUdUyhqqySCZhpp3SMjEcsZYJIzvSMzvNGA4E4HFVLVvhX6X07eNGQU1Ldq63X6tqaWWrbZbgHwsip3S78cQpy6beduAbo+SXOGQ0kcRl0Jea3Qu1u30ulNXOo7rqnT1yoIb9BPU1dXSiekbLI5zy9ziOQkc5rjvMZu74b1Lu+3+C42vVey7V1LZbnfbfp69TyXCns9K6qqmRTUU8AkbE3ynhr3tzugkA5wg7FTzsqqeKaPe5ORoe3faWnBGRkEAg+48VkWra69t1tlHWtgnpm1MLJhDVRGKWMOaDuvYeLXDOCDxByFtICrF5xadZWOuZutFyL7ZUdeX4Y+aEn7JZKB/mlWdVjVTeeag0rRtyXitfWPwMgRxwvBOfN5ckY/avRgf9THhP4lYWdERedBERAREQEREBERBDais81caWuoDGy7UDi+nMpIZI1ww+J5GSGuHnwd1wa7Dt3BxxVlo1vaq62VlKyZksToK+0XCNpe1jgWuZLGcgtIyMjLXDiC4EFTqir1pi2agMbq2m3poxiOphkdDPGPOGysIe3zdRHUt1NVNURTX2dq8VMZ4NuyiNwc3ZvpZrgcgi0wAg/ur6h8HHZVTTRyxbOdLxyxuDmPbaYAWkcQQd1Tx0PI0nktS36Fp/V50x+P2vY4/wA08Saj2qv3+tD3Sy+Xh9/2ktG9aEVX8Saj2qv3+tD3Sxz6MqY4JHjVV+y1pIzND6P8pPl4ff8AaS0b1sRcv2WWu66w2Y6Qv1x1TeBcLpZ6OuqRTywiPlZIWPfu/FnycuOOJ4edWjxJqPaq/f60PdJ8vD7/ALSWjeibtsB2aX651VxuWgdOV9wqpHTT1VRa4XySvccuc5xbkkniSVrP8G7ZTIcv2caXcQAMm0wHgBgD5PoCn/Emo9qr9/rQ90niRK4bsmp79I09Y5xG3+bYwf5p8vD7/tJaN7Zgj0/s4sFJb6KlpbPbYcx0luoYQwEkl25FEweUSSTutGeJX7YbZUyV9RerlEIbhUsEMdMHB3NYGklrCQSC8k7zy3hnDQXBgcc1n0la7JUOqaeB8tY4EOq6uZ885B6xvvJcB7gQPcphSaqaYmmjt7TgIiLQgiIgIiICIiAiIgIiICIiAsVX81m+w78FlWGr+azfYd+CCk7BC07C9nJYSWnTduwSMEjmsfvP4n61fFRNgmfgM2dZLSfFy3ZLAAPmsfVu8MfVwV7QEREBERAREQEREBERAREQEREBERAREQFhq/ms32Hfgsyw1fzWb7DvwQUjYCANhGzgBzXgabtvlMGAf7LHxHAcP2K+qhbAMfARs33SS3xatuCW7v8A6WPzeZX1AREQEREBERAREQEREBF+OcGNLnENaBkkngAqUdYXu7AVFltlCba/jDUXCpfHJM3zPEbYzutPWMnJHWAt2HhVYt83otrrsipHTusPULH2ubu06d1h6hY+1zd2t2i1745wWXdFSOndYeoWPtc3dp07rD1Cx9rm7tNFr3xzgsu6KkdO6w9Qsfa5u7Tp3WHqFj7XN3aaLXvjnBZd1xjwpdvlf4O2hqXUsWk3aotktRzSrdHXc2dSlw+LcRyb95pIcCeGDu9e9wuHTusPULH2ubu1XNo1gvu0/Q170rebZZJLbdaZ1NLiqlLmZ4te3MXymuDXD3tCaLXvjnBZQ/AV29TbadmDaAaXlsdDpWjobRFXPqhK2ueyEteWtEbAzdDGHAz/AOIOrHH0suGbDtnV52E7NrXo+zUdlqIKQOfNVyVErX1Mzjl8jgI+s8B7gAPMr507rD1Cx9rm7tNFr3xzgsu6KkdO6w9Qsfa5u7Tp3WHqFj7XN3aaLXvjnBZd0VI6d1h6hY+1zd2nTusPULH2ubu00WvfHOCy7oqR07rD1Cx9rm7tOndYeoWPtc3dpote+OcFl3RUpup9S0Xx1baKCppm8ZG2+qkdMG+cta6MB56+GR1cMngrdQ1sFyooKumkE1NPG2WKRvU5rhkEfWCtOJg14eurqWZ0RFpRF6oJbpm7kHBFHMQR9gqvaZAGm7UAAAKSLAH2ArDqr9GLx9zm/oKr2mv0ctX3SL+gL6OD9meP6XsSSItGz3y36houeWutguFJyskPL00gezfjeWPbkcMtc1zT6CCskbyIsVXVRUNLNUzu3IYWOke7BOGgZJwOPUEGVFG6Z1HbtYaett8tFRzu13GnZVUs+45nKRPaHNduuAcMgjgQCpJARFD6i1dadJutTbrV81N0ro7bRjk3v5WoeHFjPJBxkMdxOBw4lQTCKvR7QLBLNqeJlfvSaaIF1byMn9mzCJx+r5fxbmu8je68dfBStlvFJqGz0N0oJeXoK6COpp5d1zd+N7Q5rsOAIyCDggH0oNxERUEUPctXWm0ajs1iq6vkrreGzuoafk3u5YQta6XygC1uA5p8ojOeGU0zq606xpayps9XzyGjrZ7fO7k3s3J4XmOVmHAZ3XNIyOBxwJCgmERFQWDZac7PbF7qYAe4ZOFnWDZb/h7Yvu4/EqYv2J4x+JXsWpERfNRF6q/Ri8fc5v6Cq9pr9HLV90i/oCsOqv0YvH3Ob+gqvaa/Ry1fdIv6Avo4P2Z4/pexvVEIqYJInOexsjS0ujcWuGRjII4g+8Lx1okVmzDwVr5f9P3m6012q73UWp1VW3GaqhoGPvL6d07IpHFjHhjy4uABc7ynZ4r2SqJTbDdD0ldqGpjsMf8AeBkrLnTPnlfTVAlIdIeQLzG1zi0Eua0EnzqTF0cQ2kam1B4PF81Hb9O6hvWpIpNFV17bBfq11fJRVVPJGxlQHPyQxwldlnySY+AHFSFypblsx1RoagpdY33VFNq+1XOK5w3ivdVskdFRGdtVCHcIRvDdLWYbiRoxkBdj0dsV0XoMXLoeyMa64wimq5K2olrJJYQCBEXzPe7k8E+QDu8epYtE7DND7O7o+42GxNpa10BpWyzVM1QYYScmKISvcImZA8hm6OA4cFM2Ro+DQQfB62b4Of7v0XV/ktUVt1vF0qNVbOdGUV5q9OW/U9xqIq+50EgiqBHDTPmbBHJjyHSOAG8PKwDjrUxS7N7xoOihtOzep0/pqwNL5nUNyttTXFsr3EuMZFXGGM6sMAwDnHXhbFVs3qdfaeqbRtL6D1NSmaOemFsoJ6EwPbnDw41Ejw8Z4OY5pAyOOVddrChbTLGNI2nTWh7VeNbX293u4zT0MbNSPppjHFDmUTVpDpGwMBa7A3nlxAGRkLnlo1BfrxorQNHqSrkrLjZNrAtHL1FTzmUxxGcMa+bdZyrmh27vlrS7AJAJXeHeDzoF9jp7UbLMKenrHV8U4uVUKpk7mBjnioEvK5cwBp8vBAAPUsg8H3Z83Stdppmm4YrHW1bK+WjinlY1tS0NDZoyHgxvwxvlMLSTknJJJxzZuOXVcEk9T4T/ACNdW26oglp6mKpt1U+mnjfHaYJGFsjCHN8pgzg8RkHgStXSNJddpOvNNWa5at1LR25+za03OWO2XWWmdLVvllaZ3Pad4vx1nPlYG9vYAHcqvZVpWtvl8vEtpb0lfLf0Xcp45pGc6p93d3XhrgC4N4B+N4DgCAtix7OtPabu1Lc7db+b11NaYbHFLy0jt2jicXRxYc4g4Lid4jeOeJKuaPLds2lXTUmmtlMmu9V3+x6auFjruWu1iklhnrbpDM2ONsskLS8ZibI8NGA92c5xhegPByp9QU+xXS41Sa436SGSapdcnvdUu35XvaZN8ktcWOaS39UndAAGBT9pXg8Gqt2lqDRdjsvMLLDUwMhuN6ulBNGyV7XkMnpnlzmlzSS14dk7uC3CmNDaB2p6L0jbbRHrSwVr4GyGSS7WurrpGl0r3iNsxrGOcxjXNY0vBdhuSeOBIiYnWP3aQceEVsb98N8H/wCeFclhuNyodlNdFartW2Wet2uT2+Wqt8vJzNimu7mPAPEcWuPAgj0grv7dnMuq2Wuo18LRfbtZ7g2vtdXaaSeg5q9oGOueRxJIORvbrhgFpxx+37FNFvrrhV9CMjmr7rT3up5KolYyStgfvxT7jXhodvcTgAPPyg5W0yODXjS90o73tst1NrvWUVJpOz011s7TfZ3ugqJKaaRxe9xL5Wb0DcRyFzQHO4ceHpDZ7eqjUmgNM3esINXX2ymqpi0YBe+JrnYHm4krHUbOtPVVZqeqlt+9PqWljorq/lpBzmFjHxsbjewzDZHjLMHj15AUxZ7RSWC0UNroIuQoaKBlNTxbxduRsaGtbkkk4AAySSrEWG4sGy3/AA9sX3cfiVnWDZb/AIe2L7uPxKyxfsTxj8SvYtSIi+aiL1V+jF4+5zf0FV7TX6OWr7pF/QFcaiCOqgkhlbvxSNLHNPnBGCFQ4aW/6Zp4bc2yTXynp2NihrKOoha57AMN5Rsr2YfgccEg9fDO6PoZPMTRNF7Te+ubfllGuLJ1FCdLX72MuvaqLv06Wv3sZde1UXfrfmeaPVHUsm0UJ0tfvYy69qou/Tpa/exl17VRd+mZ5o9UdSybRQnS1+9jLr2qi79Olr97GXXtVF36Znmj1R1LJtFCdLX72MuvaqLv1+PvN9jY5ztG3UNaMk85o+/TM80eqOpZOIqpp7Wtw1XYLZe7XpO61NsuVLFWUs/L0jOUikYHsduumBGWuBwQCPOFIdLX72MuvaqLv0zPNHqjqWTaKE6Wv3sZde1UXfp0tfvYy69qou/TM80eqOpZNooTpa/exl17VRd+nS1+9jLr2qi79MzzR6o6lk2ihOlr97GXXtVF36dLX72MuvaqLv0zPNHqjqWTawbLf8PbF93H4lRrajUlw+Ig07LbJH8OdXGpgdHF/wA27FI9ziOJDeGSMFzc5FusdohsFmorbTue6GlhbC10hy52BjJPnJ6z7ytOPMU4eZeJmZidUxOy+7ibIbyIi+cxEREBERAREQEREBYqv5rN9h34LKsNX81m+w78EFM2Ejd2IbPRjdxp23DG7u4/s0fmwMf9B9QV5VE2CM5PYXs6YGuaG6ctw3XN3SP7LHwIycfVlXtAREQEREBERAREQEREBERAREQEREBERAWGr+azfYd+CzLDV/NZvsO/BBSNgJB2EbOC05adN23BLQ3I5rH5h1fUr6qLsGDxsN2diQyGTxct28ZRh5PNo87w9PpV6QEREBERAREQEREBERAREQEREBERARRN31bY9PyNjud5oLdI7GGVVSyNxz1YDiCVF/Cro32qs/bY/wA1upwMWuL00zMcJW0rUq/q/W+ndHUrOn7/AGux85Y8QdJVkdPyu6Bvbu+4b2N5ucdWR6Vq/Cro32qs/bY/zXD/AAx7BovbzsRu1ppNR2aXUFv/AN42l3PY94zsBzGDn/iNLm46slpPUstGx+5PKVzZ3Ok+DXquw6h2L6Jo7Pebfc6i3aftsVXBRVUcr6Z3NmgNka1ziw5Y4YJ/VPXgrqK8bf7P/SmmNiWyGauvl9tlBqjUcraqtpp6tjJKeJm82CJzSeDgHPcfRymD1L0/8Kujfaqz9tj/ADTRsfuTykzZ3LUiqvwq6N9qrP22P81v2rW+nb7PyFtv1tr5/wD4qarjkf8Aug5UnAxaYvVRMRwlLSm0RFoQREQEREBERAREQEREBcZ2jbTKq51s9osdTJSUUDnRVNdA7dkmeOBZG4cWtacguHEkYGAMu6DtIvk2ndC3qvpn8nVMpyyB/wD7JXkMY79jnA/sXnqmp2UtPHDGMMjaGge4Lpvg+R0Yt8fEi9tUcV2Rd8wUcFM5zoomMe45c8DynH0k9ZPvKzIi7JgIq9q/W9HpAUUUlLW3O4Vz3MpbdbohJPNujLyASGhrRjLnEAZHHJCr0226yU9tgqZLfd21cl0bZ32zmg53DVOidKxr2b2MOa0Yc0keUDnGSNNWNh0zaqUdCRUWLbFY2WK+XK4QV9nksszKest9bCOcskeGmJrWsc4PL99u7uk5yorSG0e56q2sVlrkt9zslsiscVULfdaaOKXljO9vKAtLiQW4GN7AIPAHKx+fh3iInb/v0rp6xVFJBVtDZoY5QDkB7QcFZUXoFu0NtKqtJTx0t1qpauxHyTLUPL5KTj8reJyYx5wc7o4jgMLu4ORkcQvLLmh7S1wDmkYIPUV27YxdpLnoKkimeZJaGSSiLz1lrHEMz79zc/auS+M5HRREZRhxbXaevVltheURFygIiICIiAiIgIiIKptUtk132e3yCna6SdtPy8cbPlPdGRIGj3ksx+1cCilZPEySNwcx4DmuHnB6l6oXBNoWgJdF1M1dRRGTT8jnSEsb8yJOS1wH/D68O6m9RwACep+C5VRRfJ65tebx06G2HN71r7TGm6zml31HabXV7ofyFbXRQybp6juucDjgeK0Phd0L7aae/isH/erNyVPVBsu5FMHDg/AdkfWnMab1eL9wLqpjEvqmOX9sXH9o9hoNpt305qewUlm2h0NndUUlZaW1cEjJGytYd5j3EsEjC1pw4jId1hZTs+qJLfo+W1aKo9KOptSxXCtoaSWDyIGQzMEryzDXO8to3W7xGfPxXX44mQgiNjWA8cNGF9LRo1M1TVVtnh4f+9m9HE9Y7NNR3bUOsbrQUkTpulLPdrXHPM1sdY6lYN+NxBJZkgjLgOOPNxUja7jcqLaXV6x1bbINF2Z1kitrJblc6ZwMwqHv3SWvwODuHpx6eA62vmSNkrd17Wvb6HDIV0aIqzqZnbfwveZ/aqr8LmhTn++mnuH/ANrB/wB62rXtI0le6+Kht2qbLX1sxIjpqW4QySPIBJw1riTwBPD0Kc5lT+rxfuBfraaCI74ijYRx3g0DC3RGJfXMcv7RlXaNiFA+l0FDUvBbz+omrGA+djnYYfqLGtd+1cz0XomfaBOMb8Vh4iorW8OVGcGOI+cniC4cG+nK9Dwwx00McMTGxRRtDGMYMNaAMAAeYLmvjWVUTTGT0zeb3nw8GcaofaIi5EEREBERAREQEREBERBUbpsm0nd6h1RNZo4JnO3nPopJKYuPpdyTm5P1qP8AgN0j6rX/AMWq+9V+ReynLMppi1OJVEcZW8qD8BukfVa/+LVfep8BukfVa/8Ai1X3qvyLLTsq/lq5yXlQfgN0j6rX/wAWq+9T4DdI+q1/8Wq+9V+RNOyr+WrnJeVB+A3SPqtf/FqvvVt0Gx3R9vmbKLOKp4II5/US1TQR1Hdlc4fyVzRYzluVVRacWrnJeXyxjY2NYxoa1owGgYAHoX0iLxoIiICIiAiIg//Z",
            "text/plain": [
              "<IPython.core.display.Image object>"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "from IPython.display import Image, display\n",
        "from langgraph.graph import StateGraph, START, END\n",
        "from langgraph.graph.state import CompiledStateGraph\n",
        "\n",
        "# Node\n",
        "def tool_calling_llm(state: MessagesState):\n",
        "    return {\"messages\": [llm_with_tools.invoke(state[\"messages\"])]}\n",
        "\n",
        "# Build graph\n",
        "builder: StateGraph = StateGraph(MessagesState)\n",
        "builder.add_node(\"tool_calling_llm\", tool_calling_llm)\n",
        "builder.add_edge(START, \"tool_calling_llm\")\n",
        "builder.add_edge(\"tool_calling_llm\", END)\n",
        "graph: CompiledStateGraph  = builder.compile()\n",
        "\n",
        "# View\n",
        "display(Image(graph.get_graph().draw_mermaid_png()))"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "e8909771-7786-47d6-a53d-6bbc3b365737",
      "metadata": {
        "id": "e8909771-7786-47d6-a53d-6bbc3b365737"
      },
      "source": [
        "If we pass in `Hello!`, the LLM responds without any tool calls."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 16,
      "id": "983e2487-c0a5-40a2-afbc-aa53ff49fefc",
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "983e2487-c0a5-40a2-afbc-aa53ff49fefc",
        "outputId": "d1f2e3f8-9bce-4ce1-857c-73593202a723"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "================================\u001b[1m Human Message \u001b[0m=================================\n",
            "\n",
            "Hello!\n",
            "==================================\u001b[1m Ai Message \u001b[0m==================================\n",
            "\n",
            "Hello! How can I help you today?\n"
          ]
        }
      ],
      "source": [
        "messages = graph.invoke({\"messages\": HumanMessage(content=\"Hello!\")})\n",
        "for m in messages['messages']:\n",
        "    m.pretty_print()"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "3588688b-efd9-4dbc-abf2-7903e3ef89ba",
      "metadata": {
        "id": "3588688b-efd9-4dbc-abf2-7903e3ef89ba"
      },
      "source": [
        "The LLM chooses to use a tool when it determines that the input or task requires the functionality provided by that tool."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 17,
      "id": "7fe8b042-ecc8-426f-995e-cc1bbaf7cacc",
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "7fe8b042-ecc8-426f-995e-cc1bbaf7cacc",
        "outputId": "0ecd995c-b19d-4517-e900-4044aae6fd59"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "================================\u001b[1m Human Message \u001b[0m=================================\n",
            "\n",
            "Multiply 4 and 2!\n",
            "==================================\u001b[1m Ai Message \u001b[0m==================================\n",
            "Tool Calls:\n",
            "  multiply (f52519f3-7170-44df-a72e-86ff1f6747cc)\n",
            " Call ID: f52519f3-7170-44df-a72e-86ff1f6747cc\n",
            "  Args:\n",
            "    a: 4.0\n",
            "    b: 2.0\n"
          ]
        }
      ],
      "source": [
        "messages = graph.invoke({\"messages\": HumanMessage(content=\"Multiply 4 and 2!\")})\n",
        "for m in messages['messages']:\n",
        "    m.pretty_print()"
      ]
    }
  ],
  "metadata": {
    "colab": {
      "provenance": []
    },
    "kernelspec": {
      "display_name": "Python 3",
      "language": "python",
      "name": "python3"
    },
    "language_info": {
      "codemirror_mode": {
        "name": "ipython",
        "version": 3
      },
      "file_extension": ".py",
      "mimetype": "text/x-python",
      "name": "python",
      "nbconvert_exporter": "python",
      "pygments_lexer": "ipython3",
      "version": "3.12.6"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 5
}
